﻿/*!
* 开始写个html5的游戏引擎,当然只是简单的2D显示,事件,图形等游戏引擎元素
* 基于html5 canvas画布为渲染
* jQuery JavaScript Library v1.4.4
* http://jquery.com/
* by byz
*/

/** 每秒帧数
    @type Number
*/
var FPS = 30;

/** 两帧间的秒数
@type Number
*/
var SECONDSBETWEENFRAMES = 1 / FPS;

var ContName = 'container'; //控制器id(div)
var ContNameID = '#' + ContName;
var canvasName = 'canvas'; //画布id
var debugmsg = 'debugInfo';

/**引擎全局引用
*/
var g_fengine;

function FEngine() {
    /** 对画布元素的引用
    @type HTMLCanvasElement
    */
    this.canvas = null;
    /** 对画布元素2D上下文的引用
    @type CanvasRenderingContext2D
    */
    this.context2D = null;
    /** 对内存中用作后台缓冲区的画布的引用
    @type HTMLCanvasElement
    */
    this.backBuffer = null;
    /** 对后台缓冲画布的2D上下文的引用
    @type CanvasRenderingContext2D
    */
    this.backBufferContext2D = null;
    /** 保存游戏中对象的数组
    @type Arary  MapClass map类
    */
    this.gameObjects = new MapClass();
    /** 对象索引,累加
    @type int
    */
    this.gameOjbectsIndex = 0;
    /** 保存游戏窗口
    */
    this.gameGameForms = new MapClass();
    /** 上一次帧被渲染的时间
    @type Date
    */
    this.lastFrame = new Date().getTime();

    //已经运行的时间
    this.currentTime;
    //显示宽度
    this._screenWidth;
    //显示高度
    this._screenHeight;
    //画面偏移
    this._offx;
    this._offy;
    //鼠标位置
    this._mousex;
    this._mousey;

    //当前拾取
    this._pickObj = null;
    //当前拾取(持续
    this._pickObjs = null;
    //当前点击
    this._cdownObjs = null;

    //初始化引擎
    //传入游戏的主画布,窗口大小
    //canvas:画布
    //width:窗口宽
    //height:窗口高
    this.init = function (canvas, width, height, offx, offy) {
        this.canvas = canvas;
        this.context2D = canvas.getContext('2d');

        //设置为1像素
        //this.context2D.lineWidth = 1;

        this._screenWidth = width;
        this._screenHeight = height;
        this._offx = offx;
        this._offy = offy;
        this._iframe = 0;
        //缓存用画面
        this.backBuffer = document.createElement('canvas');
        this.backBuffer.width = this.canvas.width;
        this.backBuffer.height = this.canvas.height;
        this.backBufferContext2D = this.backBuffer.getContext('2d');
    }

    //帧更新
    this.frame = function () {
        // 计算从上一帧到现在的时间
        var thisFrame = new Date().getTime();
        var dt = (thisFrame - this.lastFrame) / 1000;
        this.lastFrame = thisFrame;
        this.currentTime += thisFrame;

        // 清理绘制上下文
        this.backBufferContext2D.clearRect(0, 0, this.backBuffer.width, this.backBuffer.height);
        this.context2D.clearRect(0, 0, this.canvas.width, this.canvas.height);

        // 首先更新所有游戏对象
        for (x in this.gameObjects.toArray()) {
            if (this.gameObjects.getk(x).frame) {
                this.gameObjects.getk(x).frame(dt, this.backBufferContext2D);
            }
        }

        // 然后绘制所有游戏对象
        for (x in this.gameObjects.toArray()) {
            if (this.gameObjects.getk(x).draw) {
                this.gameObjects.getk(x).draw(dt, this.backBufferContext2D);
            }
        }
        //普通文字
        fps = Math.round(1 / dt);
        this.context2D.font = "10pt 宋体";
        this.context2D.fillText("帧数(fps):" + fps, 10, 10);
        this.context2D.fillText("鼠标位置: (" + this._mousex + " , " + this._mousey + ")", 10, 25);

        this.context2D.fillText("对象数(image):" + this.gameObjects.count(), 120, 10);
        this.context2D.fillText("拾取对象数(image):" + this.picklist().length, 250, 10);

        //拾取事件判定
        pickobj = this.pickfirst();
        if (pickobj) {
            for (x in this.gameObjects.toArray()) {
                if (this.gameObjects.getk(x).getID() != pickobj.getID()) {
                    if (this.gameObjects.getk(x).set_pick) {
                        this.gameObjects.getk(x).set_pick(false);
                    }
                }
            }

            pickobj.set_pick(true);
            this.context2D.fillText("拾取对象:" + pickobj.getID() + " " + pickobj.getX() + " " + pickobj.getY() +
                " " + pickobj.getConterX() + " " + pickobj.getConterY(), 160, 30);
        }
        else {
            for (x in this.gameObjects.toArray()) {
                if (this.gameObjects.getk(x).set_pick) {
                    this.gameObjects.getk(x).set_pick(false);
                }
            }
        }

        //用户密码
        //this.context2D.fillText("用户名: " + localStorage.loginname + " 昵称:" + (sessionStorage.nickname), 20, 60);
        //艺术字
        /*this.context2D.font = "10pt 微软雅黑";
        this.context2D.strokeStyle = "blue"; // stroke color    
        this.context2D.strokeText("艺术字:蓝色雅黑", 20, 12);*/

        // 将后台缓冲复制到当前显示的画布
        this.context2D.drawImage(this.backBuffer, 0, 0);
        //this.context2D.restore();
    }

    /**
    向gameObjects集合中添加一个GameObject
    @param gameObject The object to add
    */
    this.addGameObject = function (gameObject) {
        //索引+1 保存所有对象的索引唯一
        this.gameOjbectsIndex += 1;2
        gameObject.setID(this.gameOjbectsIndex);

        if (gameObject._isform) {
            this.addGameForm(gameObject);
        }

        this.gameObjects.add(gameObject._id, gameObject);
        this.sortGameObject();
    };
    /**
    对gameObjects集合进入排序
    @sort The gameObjects
    */
    this.sortGameObject = function () {
        this.gameObjects.sort();
    }
    /**
    从gameObjects集合中删除一个GameObject
    @param gameObject The object to remove
    */
    this.removeGameObject = function (gameObject) {
        this.gameObjects.del(gameObject.getID());
    }

    /**
    向gameGameForms集合中添加一个GameObject
    @param gameObject The object to add
    */
    this.addGameForm = function (gameObject) {
        //索引+1 保存所有对象的索引唯一
        this.gameGameForms.add(gameObject._id, gameObject);

        gameObject.zLayer = this.gameGameForms.count();

        gameObject.click(this.sortGameForm, { arg1: gameObject});

        this.sortGameForm(gameObject);
    };
    /**
    对gameGameForms集合进行排序,传入的参数是在最上面的窗口,然后把其它的窗口放置于此窗口下面
    @sort The gameObjects
    */
    this.sortGameForm = function (gameObject, gameForms) {
        if (gameObject) {
            gameForms = g_fengine.gameGameForms;
            //传递进来的窗口与最前面的窗口交换层级,
            gameForms.sort_layer();
            if (gameForms.count() > 0) {
                templayer = gameObject.zLayer;
                gameObject.setLayer(gameForms.getk(0).zLayer);
                gameForms.getk(0).setLayer(templayer); /**/
            }
            g_fengine.sortGameObject();
        }
    }
    /**
    从gameGameForms集合中删除一个GameObject
    @param gameObject The object to remove
    */
    this.removeGameForm = function (gameObject) {
        this.gameGameForms.del(gameObject.getID());
    }
    this.hideGameForm = function (gameObject) {
        gameObject.hide();
        //alert(gameObject.getID());
    }
    

    //鼠标点击
    this.click = function (e) {
        for (x in this.gameObjects.toArray()) {
            if (this.gameObjects.getk(x)._click) {
                this.gameObjects.getk(x)._click(this._mousex, this._mousey);
            }
        }
        //e.which 1 = 鼠标左键；2 = 鼠标中键；3 = 鼠标右键。
    }
    //键盘按下
    this.mousedown = function (e) {
        this._pickObjs = null;
        //获得当前选中并且能拖动的实体
        var x = this.gameObjects.count() - 1;
        for (; x >= 0; x--) {
            obj = this.gameObjects.getk(x);
            if (obj.jugePick(this._mousex, this._mousey)) {
                if (obj.drag()) {
                    this._pickObjs = obj;
                }
                this._cdownObjs = obj;
                this._cdownObjs.on_mousedown(this._mousex, this._mousey);
                break;
            }
        }
    }
    //键盘按起
    this.mouseup = function (e) {
        if (this._pickObjs) {
            //更新鼠标状态
            document.body.style.cursor = 'default';
            this._pickObjs = null;
        }
        if (this._cdownObjs) {
            this._cdownObjs.on_mouseup(this._mousex, this._mousey);
            this._cdownObjs = null;
        }
    }
    //鼠标移动
    this.mousemove = function (e) {
        //得到鼠标偏移量
        offx = this._mousex - (e.pageX - this._offx);
        offy = this._mousey - (e.pageY - this._offy);
        //更新全局鼠标位置
        this._mousex = (e.pageX - this._offx);
        this._mousey = (e.pageY - this._offy);
        //拖动当前鼠标的对象
        if (this._pickObjs) {
            this._pickObjs.moveOff(offx, offy);
        }
    }
    //键盘按下
    this.keydown = function (e) {
    }
    //键盘按起
    this.keyup = function (e) {
    }
    //键盘释放
    this.keypress = function (e) {
        //document.getElementById(debugmsg).innerHTML = "按键: " + e.keyCode;
    }
    //返回拾取到的所有对象
    this.picklist = function (first) {
        var first = first || false;
        var objlist = new Array();

        var x = this.gameObjects.count()     - 1;
        for (; x >= 0; x--) {
            obj = this.gameObjects.getk(x);
            if (obj.jugePick(this._mousex, this._mousey)) {
                if (first)
                    return obj;
                objlist.push(obj);
            }
        }
        if (first)
            return null;
        return objlist;
    }
    //返回拾取到的第一个对象
    this.pickfirst = function () {
        return this.picklist(true);
    }
}

//对象拾取:返回拾取到的对象数组
function FPicklist() {
    return g_fengine.picklist();
}

//事件初始化
function finit_event() {
    //鼠标点击(左、中键)
    $(ContNameID).click(function (e) { g_fengine.click(e); });
    //鼠标点击(右键)
    $(ContNameID).on("contextmenu", function (e) {
        //在这里书写代码，构建个性右键化菜单 
        g_fengine.click(e);
        //取消默认的右键菜单 
        return false;
    });

    //鼠标移动
    $(ContNameID).mousemove(function (e) { g_fengine.mousemove(e); });
    $(ContNameID).mousedown(function (e) { g_fengine.mousedown(e); });
    $(ContNameID).mouseup(function (e) { g_fengine.mouseup(e); });

    //键盘事件:需要绑定body
    $('body').keydown(function (e) { g_fengine.keydown(e); });
    $('body').keyup(function (e) { g_fengine.keyup(e); });
    $('body').keypress(function (e) { g_fengine.keypress(e); });
}

function fengine_init(_w, _h) {
    //创建div
    var createDiv = document.createElement("div");
    createDiv.setAttribute("id", ContName);
    createDiv.style.border = "1px solid";
    document.body.appendChild(createDiv);
    //创建画布
    var createCanvas = document.createElement("canvas");
    createCanvas.setAttribute("id", canvasName);
    document.getElementById(ContName).appendChild(createCanvas); /**/

    //设置div大小
    $(ContNameID).css("width", _w);
    $(ContNameID).css("height", _h);
    //设置画布大小
    document.getElementById(canvasName).setAttribute("height", _h);
    document.getElementById(canvasName).setAttribute("width", _w);
    //设置画面居中
    offx = (document.body.scrollWidth - _w) / 2; //x偏移量
    offy = 0; //y偏移量
    $(ContNameID).css("margin-left", offx);
    $(ContNameID).css("margin-top", offy);
    $(ContNameID).css("position", "absolute");
    offx = document.getElementById(ContName).offsetLeft;
    offy = document.getElementById(ContName).offsetTop;

    //事件初始化
    finit_event();

    //初始化
    g_fengine = new FEngine();
    g_fengine.init(document.getElementById(canvasName), _w, _h, offx, offy);
    //渲染主循环
    setInterval(function () { g_fengine.frame(); }, Math.floor(SECONDSBETWEENFRAMES * 1000));
}
//初始化
$(window).ready(function () {
    
});